package com.minigame.chess.gobang.entity.domain;

import com.minigame.chess.gobang.enums.Color;
import com.minigame.chess.gobang.enums.Degree;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Position {
    /**
     * 横坐标
     */
    private Integer x;
    /**
     * 纵坐标
     */
    private Integer y;


    /**
     * 是否存在一条线上连续的5个同色棋子
     * @param degree 角度
     * @param chessMap 所有棋子
     * @param color 棋子颜色
     * @return 是否存在一条线上连续的5个同色棋子
     */
    public boolean hasLine(Degree degree, Map<Position, Color> chessMap, Color color) {
        int c = summaryLine(1, degree, false, chessMap, color);
        return c >= 5 || summaryLine(c, degree, true, chessMap, color) >= 5;
    }

    /**
     * 统计一条线上的同色棋子
     * @param count 一条线上的同色棋总数
     * @param degree 角度
     * @param reverse 是否反向
     * @param chessMap 所有棋子
     * @param color 棋子颜色
     * @return 一条线上一个方向的同色棋子数量
     */
    public int summaryLine(int count, Degree degree, boolean reverse, Map<Position, Color> chessMap, Color color) {
        Position pointer = this;
        while (pointer.hasNext(degree, reverse, color, chessMap) && count < 5) {
            pointer = pointer.next(degree, reverse);
            count++;
        }
        return count;
    }

    /**
     * 是否有下一个棋子
     * @param degree 角度
     * @param reverse 是否反向
     * @param color 指定棋子颜色
     * @param chessMap 所有棋子
     * @return 是否有下一个棋子
     */
    public boolean hasNext(Degree degree, boolean reverse, Color color, Map<Position, Color> chessMap) {
        return exist(next(degree, reverse), color, chessMap);
    }

    /**
     * 是否存在棋子
     * @param position 指定位置
     * @param color 指定棋子颜色
     * @param chessMap 所有棋子
     * @return 是否存在棋子
     */
    public boolean exist(Position position, Color color, Map<Position, Color> chessMap) {
        return chessMap.get(position) == color;
    }

    /**
     * 下一个位置
     * @param degree 角度
     * @param reverse 是否反向
     * @return 下一个位置
     */
    public Position next(Degree degree, boolean reverse) {
        int x = reverse ? this.x - degree.getOffsetX() : this.x + degree.getOffsetX();
        int y = reverse ? this.y - degree.getOffsetY() : this.y + degree.getOffsetY();
        return new Position(x, y);
    }
}
